﻿using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text.Json;
using MeiWinForms.comm;
using static MeiWinForms.communication.Comm;

namespace MeiWinForms.communication;

using Handler = Func<dynamic, dynamic>;

public class Client
{
    private readonly string _name;
    private Socket? _sender;
    private Socket? _receiver;
    private readonly Logger _logger;

    private readonly Dictionary<string, Handler> _handlers = new();

    private static readonly Dictionary<string, Client> Instances = new();

    public static Client GetClient(string name = "controller")
    {
        if (Instances.TryGetValue(name, out Client? value))
        {
            return value;
        }

        return Instances[name] = new Client(name);
    }

    private Client(string name)
    {
        _name = name;
        _logger = Logger.GetLogger($"client[{_name}]", Logger.Level.Debug);
    }

    ~Client()
    {
        Close();
    }

    /// <summary>
    /// 向服务器注册
    /// </summary>
    /// <param name="clientType">可选项有：sender、receiver</param>
    [MethodImpl(MethodImplOptions.Synchronized)]
    private Socket Register(string clientType)
    {
        _logger.Info($"客户端{_name}正在向服务器注册{clientType}");
        var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        while (true)
        {
            try
            {
                socket.Connect(Host, Port);
                break;
            }
            catch (SocketException e)
            {
                _logger.Warning($"连接服务器失败，即将重连：{e.Message}");
                Thread.Sleep(ReconnectTime * 1000);
            }
        }

        SendMsg(socket, Message.Serialize("register", new
            {
                name = _name,
                client_type = clientType
            }
        ));
        _logger.Info($"客户端[{_name}] {clientType} 成功连接服务器");
        return socket;
    }

    [MethodImpl(MethodImplOptions.Synchronized)]
    public JsonElement Send(string cmd, dynamic value)
    {
        _sender ??= Register("sender");

        try
        {
            string msg = Message.Serialize(cmd, value);
            SendMsg(_sender, msg);
            _logger.Debug($"客户端[{_name}]发送消息到服务器：{msg}");
            string ret = RecvMsg(_sender);
            _logger.Debug($"客户端[{_name}]收到服务器回响应：{ret}");
            return Message.Deserialize(ret).value;
        }
        catch (SocketException e)
        {
            _logger.Warning($"客户端[{_name}]连接服务器失败：{e}，将在{ReconnectTime}秒后重试");
            Thread.Sleep(ReconnectTime * 1000);
            return Send(cmd, value);
        }
    }

    public void Subscribe(string cmd, Handler handler)
    {
        _handlers.Add(cmd, handler);
    }

    public void Listen()
    {
        _receiver = Register("receiver");
        while (_receiver.Connected)
        {
            try
            {
                string msg = RecvMsg(_receiver);
                _logger.Debug($"客户端[{_name}]收到服务器消息：{msg}");
                Message message = Message.Deserialize(msg);
                dynamic? ret = _handlers[message.cmd](message.value);
                _logger.Debug($"客户端[{_name}]向服务器回响应：{ret}");
                SendMsg(_receiver, Message.Serialize("result", ret));
            }
            catch (SocketException e)
            {
                _logger.Error($"客户端[{_name}]接受消息失败，将在{ReconnectTime}秒后重连：{e}");
                Thread.Sleep(ReconnectTime * 1000);
                _receiver = Register("receiver");
            }
            catch (Exception e)
            {
                _logger.Error($"客户端[{_name}]接受消息失败：{e}");
                SendMsg(_receiver, Message.Serialize("result", new
                    {
                        error = e.ToString()
                    }
                ));
            }
        }
    }

    public void Close()
    {
        _sender?.Close();
        _receiver?.Close();
    }
}